#ifndef _KC_NODE__H_KC_2010_
#define _KC_NODE__H_KC_2010_

#include <iostream>
#include <vector>
#include <stdexcept>

namespace kc_sf {

template<typename T>
class Node {
public:

	explicit Node(const T &content) :
		n_parent(NULL), n_object(content) {
	}

	// ---

	~Node() {
		deleteChildren();
	}

	// ---

	void addChild(const T & content) {
		n_children.push_back(Node(content));
		n_children[n_children.size() - 1].n_parent = this;
	}

	// ---

	void addChild(const Node<T> & content) {
		n_children.push_back(content);
		n_children[n_children.size() - 1].n_parent = this;
	}

	// ---

	void deleteChildren() {
		for (unsigned int i = 0; i < n_children.size(); ++i) {
			n_children[i].deleteChildren();
		}
		n_children.clear();
	}

	// ---

	unsigned int childrenNr() const {
		return n_children.size();
	}

	// ---

	Node<T> & child(unsigned int i) { // throws std::out_of_range
		if(i > n_children.size())
			throw std::out_of_range("Node.h child(). Próba dostępu do nieistniejącego dziecka.");
		return n_children[i];
	}

	// ---

	const Node<T> & child(unsigned int i) const { // throws std::out_of_range
		if(i > n_children.size())
			throw std::out_of_range("Node.h child(). Próba dostępu do nieistniejącego dziecka.");
		return n_children[i];
	}

	Node<T> * parent() {
		return n_parent;
	}

	// ---

	const Node<T> * parent() const {
		return const_cast<const Node<T> *> (n_parent);
	}

	// Operator konwersji ---

	operator T() {
		return n_object;
	}

	T & get() {
		return n_object;
	}

	const T & get() const {
		return n_object;
	}

protected:

	Node<T> * n_parent;
	T n_object;
	std::vector<Node<T> > n_children;

	// ---

	int findChildIndex(const Node &node) const {
		for (int i = 0; i < n_children.size(); ++i) {
			if (n_children[i] == node)
				return i;
		}
		return -1;
	}
};

}

#endif // _KC_NODE__H_KC_2010_
